﻿
using System.Collections.Generic;
using System;
using UnityEditor;
using UnityEngine;
using static Unity.Burst.Intrinsics.X86.Avx;

namespace lights.polytool.editor
{
    public class polyeditor
    {
        public bool active
        {
            get;
            private set;
        }
        comp_poly target;
        EditorWindow window;

        Vector3 EditorCenter;

        int pickedpoint = -1;
        bool mouseselect;
        public void BeginEdit(comp_poly target)
        {
            this.target = target;
            this.EditorCenter = target.transform.position;
            this.pickedpoint = -1;
            this.mouseselect = false;
            this.active = true;
            Tools.current = Tool.None;
            SceneView.lastActiveSceneView.Focus();
            this.window = EditorWindow.focusedWindow;
            this.window.Repaint();
        }
        public void EndEdit()
        {
            this.active = false;
            this.window.Repaint();
        }
        public void Draw()
        {
            if (this.active)
            {
                Handles.color = new Color(0, 0, 0, 0.5f);
                Handles.DrawSolidDisc(EditorCenter, Vector3.back, 10);

                Handles.color = new Color(1, 1, 1, 1);

                var thick = 3.0f;
                if (target.points != null)
                {

                    for (var i = 0; i < target.points.Count; i++)
                    {
                        var p1 = target.points[i];
                        var p13 = EditorCenter + (Vector3)p1;
                        DrawPointTag(p13, i == pickedpoint);

                        if (target.points.Count >= 2)
                        {
                            var next = i + 1;
                            if (next >= target.points.Count)
                                next = 0;
                            var p2 = target.points[next];

                            var p23 = EditorCenter + (Vector3)p2;

                            Handles.color = Color.white;
                            Handles.DrawLine(p13, p23, thick);
                        }
                    }
                }

                //lock pick objects on scene
                var id = GUIUtility.GetControlID(FocusType.Passive);
                HandleUtility.AddDefaultControl(id);


                var evt = Event.current;
                var type = evt.GetTypeForControl(id);
                switch (type)
                {
                    case EventType.MouseDown:
                        {
                            OnMouseDown(evt.mousePosition);
                        }
                        break;
                    case EventType.MouseUp:
                        {
                            OnMouseUp(evt.mousePosition);
                        }
                        break;
                    case EventType.MouseDrag:
                        {
                            OnMouseMove(evt.mousePosition);
                        }
                        break;
                }

            }

        }

        DateTime lastdowntime = DateTime.Now;
        void OnMouseDown(Vector2 mousePosition)
        {

            bool dbclick = false;
            if ((DateTime.Now - lastdowntime).TotalMilliseconds < 250)
            {
                dbclick = true;
            }
            lastdowntime = DateTime.Now;


            var ray = HandleUtility.GUIPointToWorldRay(mousePosition);
            var plane = new Plane(Vector3.back, EditorCenter);
            if (plane.Raycast(ray, out float distance))
            {
                var point = ray.origin + ray.direction * distance;


                var tp = point - this.EditorCenter;

                var lastpick = this.pickedpoint;
                //test if is pick a point
                if (TrySelectPoint(tp))
                {
                    mouseselect = true;
                    if (lastpick == this.pickedpoint && dbclick)
                    {
                        mouseselect = false;
                        this.RemovePickPoint();
                    }

                    this.window.Repaint();
                    return;
                }
                else
                {
                    if (dbclick)
                    {
                        //create a point

                        CreatePoint(tp);
                        this.window.Repaint();
                    }
                    return;
                }
            }




        }
        bool TrySelectPoint(Vector2 point)
        {
            var comp = this.target as comp_poly;
            if (comp.points.Count == 0)
            {
                return false;
            }
            for (var i = 0; i < comp.points.Count; i++)
            {
                var d = Vector2.Distance(comp.points[i], point);
                if (d < 0.5f)
                {
                    this.pickedpoint = i;
                    return true;
                }
            }
            return false;
        }
        void CreatePoint(Vector2 point)
        {
            var comp = this.target as comp_poly;
            if (comp.points == null)
            {
                comp.points = new List<Vector2>();
            }
            if (comp.points.Count < 3)
            {
                comp.points.Add(point);
            }
            else
            {
                float[] dist = new float[comp.points.Count];
                float[] dists = new float[comp.points.Count];
                for (var i = 0; i < comp.points.Count; i++)
                {
                    dist[i] = Vector2.Distance(comp.points[i], point);
                    var next = i + 1;
                    if (next >= dist.Length)
                        next = 0;
                    dists[i] = Vector2.Distance(comp.points[i], comp.points[next]);
                }

                float fdist = 10000;
                int findex = 0;
                for (var i = 0; i < comp.points.Count; i++)
                {
                    var d = dist[i];
                    var next = i + 1;
                    if (next >= dist.Length)
                        next = 0;
                    var d2 = dist[next];

                    var rdist = d + d2 - dists[i];
                    if (rdist > 0 && fdist > rdist)

                    {
                        fdist = rdist;
                        findex = i;
                    }
                }
                comp.points.Insert(findex + 1, point);
            }
        }
        void RemovePickPoint()
        {
            var comp = this.target as comp_poly;
            comp.points.RemoveAt(this.pickedpoint);
            this.pickedpoint = -1;
        }
        void DrawPointTag(Vector3 pos, bool picked)
        {
            Handles.color = picked ? Color.yellow : Color.blue;

            Handles.DrawWireDisc(pos, Vector3.back, 0.25f);
        }
        void OnMouseUp(Vector2 mousePosition)
        {
            var comp = this.target as comp_poly;
            if (this.mouseselect)
            {
                //var ray = HandleUtility.GUIPointToWorldRay(mousePosition);
                //var plane = new Plane(Vector3.back, EditorCenter);
                //if (plane.Raycast(ray, out float distance))
                //{
                //    var point = ray.origin + ray.direction * distance;


                //    var tp = point - this.EditorCenter;
                //    comp.points[this.pickedpoint] = tp;
                //    this.window.Repaint();


                //}
            }
            this.mouseselect = false;
        }
        void OnMouseMove(Vector2 mousePosition)
        {
            var comp = this.target as comp_poly;
            if (this.mouseselect)
            {
                var ray = HandleUtility.GUIPointToWorldRay(mousePosition);
                var plane = new Plane(Vector3.back, EditorCenter);
                if (plane.Raycast(ray, out float distance))
                {
                    var point = ray.origin + ray.direction * distance;


                    var tp = point - this.EditorCenter;
                    comp.points[this.pickedpoint] = tp;
                    this.window.Repaint();


                }
            }
        }
    }

}
